//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Platforms/Base/IApplication.h"

#if defined( PLATFORM_ANDROID ) or defined( ANDROID_EMULATOR )

namespace Engine
{
namespace Platforms
{

	class AndroidHwCamera;
	SHARED_POINTER( AndroidHwCamera );


	//
	// Android Hardware Camera
	//

	class AndroidHwCamera : public BaseObject, public HardwareCamera
	{
	// types
	public:
		struct ECommand
		{
			enum type
			{
				OPEN 					= 0x0001,
				CLOSE 					= 0x0002,
				START_FACE_DETECTION	= 0x0003,
				STOP_FACE_DETECTION		= 0x0004,
				AUTO_FOCUS				= 0x0005,
				UPDATE_ZOOM_INFO		= 0x0006,	// unused
				// shared
				SET_ZOOM				= 0x1001,
				SET_ZOOM_NORM			= 0x1002,
				SET_SMOOTH_ZOOM			= 0x1003,
				SET_SMOOTH_ZOOM_NORM	= 0x1004,
				SET_EXPOSURE			= 0x1005,
				SET_EFFECT				= 0x1006,
				SET_FLASH_MODE			= 0x1007,
				SET_FOCUS_MODE			= 0x1008,
				SET_SCENE_MODE			= 0x1009,
				SET_WHITE_BALANCE		= 0x1010,
				SET_ANTIBANDING			= 0x1011,
				SET_EXPOSURE_NORM		= 0x1012,
				// preview
				SET_PREVIEW_SIZE		= 0x2001,
				SET_PREVIEW_FORMAT		= 0x2002,
				SET_PREVIEW_FPS			= 0x2003,
				SET_PREVIEW_NEAR_SIZE	= 0x2004,
				SET_PREVIEW_NEAR_FPS	= 0x2005,
				//SET_PREVIEW_BUFFERS		= 0x2006,
				// picture
				TAKE_PICTURE			= 0x3000,
				SET_PICTURE_SIZE		= 0x3001,
				SET_PICTURE_FORMAT		= 0x3002,
				SET_PICTURE_NEAR_SIZE	= 0x3003,
				SET_JPEG_QUALITY		= 0x3004,
			};
		};


		typedef array< ivec2 >					ivec2_array_t;
		typedef array< ImageFormat::type >		format_array_t;
		typedef array< Face >					face_array_t;
		typedef array< Antibanding::type >		antibanding_array_t;
		typedef array< Effect::type >			effect_array_t;
		typedef array< FlashMode::type >		flashmode_array_t;
		typedef array< FocusMode::type >		focusmode_array_t;
		typedef array< SceneMode::type >		scenemode_array_t;
		typedef array< WhiteBalance::type >		whitebalance_array_t;

		
	private:
		typedef void *	surface_tex_t;


		//
		// On Image Parallel Operation
		//
		class _OnImageParallelOp : public Runnable
		{
		// variables
		private:
			AndroidHwCameraPtr			_camera;
			OnImageCallback_t const &	_callback;
			binary_array_t				_image;
			ivec2						_dim;
			ImageFormat::type			_fmt;
			
		// methods
		public:
			_OnImageParallelOp (const AndroidHwCameraPtr &obj, const OnImageCallback_t &callback,
								const uni_binbuffer_t &data, const ivec2 &dim, ImageFormat::type fmt) :
				_image(data), _dim(dim), _fmt(fmt), _camera(obj), _callback(callback)
			{}

			void Run () override
			{
				_callback.Call( _image, _dim, _fmt );
			}
		};
		
		/*
		//
		// On Frame Available Parallel Operation
		//
		class _OnFrameParallelOp : public IParallelOp
		{
		// types
		public:
			typedef void (*func_t) (const BaseObjectPtr &, uint textureId);

		// variables
		private:
			Callback< func_t >	_cb;
			void *				_surfaceTexture;

		// methods
		public:
			_OnFrameParallelOp (const BaseObjectPtr &obj, func_t func, void *surfaceTex) :
				_cb( func, obj ), _surfaceTexture(surfaceTex)
			{}

			void Process (IParallelThread *thread)
			{
				_cb.Call( 
			}
		};
		*/

		//
		// Set Static Params Parallel Operation
		//
		class _SetParamsParallelOp : public Runnable
		{
		// types
		public:
			typedef delegate< void (_SetParamsParallelOp &) >		delegate_t;


		// variables
		private:
			delegate_t				_cb;

		public:
			ivec2_array_t			previewFpsRanges;
			ivec2_array_t			previewSizes;
			ivec2_array_t			pictureSizes;
			format_array_t			previewFormats;
			format_array_t			pictureFormats;
			antibanding_array_t		antibandings;
			effect_array_t			colorEffects;
			flashmode_array_t		flashModes;
			focusmode_array_t		focusModes;
			scenemode_array_t		sceneModes;
			whitebalance_array_t	whiteBalances;
			int						minExposure;
			int						maxExposure;
			float					exposureStep;

		// methods
		public:
			_SetParamsParallelOp (const delegate_t &cb, int minExposure, int maxExposure, float exposureStep,
							  const format_arr_t &pictureFormats, const ivec2_arr_t &pictureSizes,
							  const format_arr_t &previewFormats, const ivec2_arr_t &previewSizes, const ivec2_arr_t &previewFpsRanges,
							  const antibanding_arr_t &antibandings, const effect_arr_t &colorEffects, const flashmode_arr_t &flashModes,
							  const focusmode_arr_t &focusModes, const scenemode_arr_t &sceneModes, const whitebalance_arr_t &whiteBalances) :
				minExposure(minExposure), maxExposure(maxExposure), exposureStep(exposureStep),
				pictureFormats(pictureFormats), pictureSizes(pictureSizes),
				previewFormats(previewFormats), previewSizes(previewSizes), previewFpsRanges(previewFpsRanges),
				antibandings(antibandings), colorEffects(colorEffects), flashModes(flashModes),
				focusModes(focusModes), sceneModes(sceneModes), whiteBalances(whiteBalances),
				_cb(cb)
			{
			}

			void Run () override
			{
				_cb.Call( *this );
			}
		};


	// variables
	private:
		// shared
		ivec2_array_t			_previewFpsRanges;
		ivec2_array_t			_previewSizes;
		ivec2_array_t			_pictureSizes;
		format_array_t			_previewFormats;
		format_array_t			_pictureFormats;
		antibanding_array_t		_antibandings;
		effect_array_t			_colorEffects;
		flashmode_array_t		_flashModes;
		focusmode_array_t		_focusModes;
		scenemode_array_t		_sceneModes;
		whitebalance_array_t	_whiteBalances;
		ivec2					_exposureMinMax;

		// callbacks
		OnImageCallback_t		_previewCallback;
		OnImageCallback_t		_pictureCallback;
		OnFaceDetected_t		_faceDetectedCallback;

		// state
		bool					_enabled;


	// methods
	public:
		AndroidHwCamera (const EngineSubSystemsRef ess);
		~AndroidHwCamera ();


		// Java Callbacks //
		void OnPreviewFrameAvailable (void *surfaceTexture);
		void OnPreview (const uni_binbuffer_t &data, const ivec2 &size, ImageFormat::type format);
		void OnPicture (const uni_binbuffer_t &data, const ivec2 &size, ImageFormat::type format);
		void OnZoomChanged (uint currentZoom, uint maxZoom, float nearFocus, float optimalFocus, float farFocus,
							float focalLength, float vertViewAngle, float horViewAngle);
		void OnFaceDetected (uint id, const irect &region, const ivec2 &leftEye, const ivec2 &rightEye,
								const ivec2 &mouth, int score);
		void SetStaticParams (int minExposure, int maxExposure, float exposureStep,
							  const format_arr_t &pictureFormats, const ivec2_arr_t &pictureSizes,
							  const format_arr_t &previewFormats, const ivec2_arr_t &previewSizes, const ivec2_arr_t &previewFpsRanges,
							  const antibanding_arr_t &antibandings, const effect_arr_t &colorEffects, const flashmode_arr_t &flashModes,
							  const focusmode_arr_t &focusModes, const scenemode_arr_t &sceneModes, const whitebalance_arr_t &whiteBalances);

		
		// HardwareCamera //
		// callbacks
		void SetPreviewCallback (OnImageCallback_t cb)		override	{ _previewCallback = cb; }
		void SetPictureCallback (OnImageCallback_t cb)		override	{ _pictureCallback = cb; }
		void SetFaceDetectedCallback (OnFaceDetected_t cb)	override	{ _faceDetectedCallback = cb; }

		// actions
		void Enable (bool enable)						override;
		void Open (uint cameraIndex)					override;
		void Close (bool saveState)						override;
		void StartFaceDetection ()						override		{ _SendCommand( ECommand::START_FACE_DETECTION ); }
		void StopFaceDetection ()						override		{ _SendCommand( ECommand::STOP_FACE_DETECTION ); }
		void AutoFocus ()								override		{ _SendCommand( ECommand::AUTO_FOCUS ); }

		// get params
		bool				IsEnabled ()			const override		{ return _enabled; }
		ivec2_arr_t			GetPreviewFpsRanges ()	const override		{ return _previewFpsRanges; }
		ivec2_arr_t			GetPreviewSizes ()		const override		{ return _previewSizes; }
		format_arr_t		GetPreviewFormats ()	const override		{ return _previewFormats; }
		ivec2_arr_t			GetPictureSizes ()		const override		{ return _pictureSizes; }
		format_arr_t		GetPictureFormats ()	const override		{ return _pictureFormats; }
		antibanding_arr_t	GetAntibandings ()		const override		{ return _antibandings; }
		effect_arr_t		GetEffects ()			const override		{ return _colorEffects; }
		flashmode_arr_t		GetFlashModes ()		const override		{ return _flashModes; }
		focusmode_arr_t		GetFocusModes ()		const override		{ return _focusModes; }
		scenemode_arr_t		GetSceneModes ()		const override		{ return _sceneModes; }
		whitebalance_arr_t	GetWhiteBalance ()		const override		{ return _whiteBalances; }
		ivec2				GetExposureLimits ()	const override		{ return _exposureMinMax; }
		
		// shared preview/picture parameters
		void SetZoom (uint value)						override		{ _SendCommand( ECommand::SET_ZOOM, (int)value ); }
		void SetZoomNorm (float value)					override		{ _SendCommand( ECommand::SET_ZOOM_NORM, value ); }
		void SetSmoothZoom (uint value)					override		{ _SendCommand( ECommand::SET_SMOOTH_ZOOM, (int)value ); }
		void SetSmoothZoomNorm (float value)			override		{ _SendCommand( ECommand::SET_SMOOTH_ZOOM_NORM, value ); }
		void SetExposure (int value)					override		{ _SendCommand( ECommand::SET_EXPOSURE, value ); }
		void SetExposureNorm (float value)				override		{ _SendCommand( ECommand::SET_EXPOSURE_NORM, value ); }
		void SetAntibanding (Antibanding::type value)	override		{ _SendCommand( ECommand::SET_ANTIBANDING, value ); }
		void SetColorEffect (Effect::type value)		override		{ _SendCommand( ECommand::SET_EFFECT, value ); }
		void SetFlashMode (FlashMode::type value)		override		{ _SendCommand( ECommand::SET_FLASH_MODE, value ); }
		void SetFocusMode (FocusMode::type value)		override		{ _SendCommand( ECommand::SET_FOCUS_MODE, value ); }
		void SetSceneMode (SceneMode::type value)		override		{ _SendCommand( ECommand::SET_SCENE_MODE, value ); }
		void SetWhiteBalance (WhiteBalance::type value)	override		{ _SendCommand( ECommand::SET_WHITE_BALANCE, value ); }

		// preview parameters
		void SetPreviewSize (const ivec2 &size)			override		{ _SendCommand( ECommand::SET_PREVIEW_SIZE, size.x, size.y ); }
		void SetPreviewNearSize (const ivec2 &size)		override		{ _SendCommand( ECommand::SET_PREVIEW_NEAR_SIZE, size.x, size.y ); }
		void SetPreviewFormat (ImageFormat::type fmt)	override		{ _SendCommand( ECommand::SET_PREVIEW_FORMAT, fmt ); }
		void SetPreviewFPS (uint minFPS, uint maxFPS)	override		{ _SendCommand( ECommand::SET_PREVIEW_FPS, (int)minFPS, (int)maxFPS ); }
		void SetPreviewNearFPS (float fps)				override		{ _SendCommand( ECommand::SET_PREVIEW_NEAR_FPS ); }

		// picture parameters
		void TakePicture (bool autoFocus)				override		{ _SendCommand( ECommand::TAKE_PICTURE, (int)autoFocus ); }
		void SetPictureSize (const ivec2 &size)			override		{ _SendCommand( ECommand::SET_PICTURE_SIZE, size.x, size.y ); }
		void SetPictureNearSize (const ivec2 &size)		override		{ _SendCommand( ECommand::SET_PICTURE_NEAR_SIZE, size.x, size.y ); }
		void SetPictureFormat (ImageFormat::type fmt)	override		{ _SendCommand( ECommand::SET_PICTURE_FORMAT, fmt ); }
		void SetJpegQuality (uint quality)				override		{ _SendCommand( ECommand::SET_JPEG_QUALITY, (int)quality ); }
		
	private:
		void _SendCommand (ECommand::type cmd)											{ _SendCommand( cmd, 0, 0, 0 ); }
		void _SendCommand (ECommand::type cmd, int arg0, int arg1 = 0, int arg2 = 0)	{ _SendCommand( cmd, float(arg0), float(arg1), float(arg2) ); }

		void _SendCommand (ECommand::type cmd, float arg0, float arg1 = 0.0f, float arg2 = 0.0f);
		
		//void _OnFrame (const BaseObjectPtr &, const surface_tex_t &, IParallelThread *);

		void _SetParams (_SetParamsParallelOp &);
	};


}	// Platforms
}	// Engine

#endif	// PLATFORM_ANDROID or ANDROID_EMULATOR